mod sse;

use std::{ops::Deref, sync::Arc};
use dashmap::DashMap;

use axum::{
    middleware::from_fn_with_state, response::{Html, IntoResponse}, routing::get, Router
};
use config::AppConfig;
use error::AppError;
use notif::AppEvent;
use sse::sse_handler;
use chat_core::{verify_token,DecodingKey, TokenVerify, User};
pub use notif::setup_pg_listener;
use tokio::sync::broadcast;
mod error;
mod config;
mod notif;

pub type UserMap = DashMap<u64, broadcast::Sender<Arc<AppEvent>>>;


#[derive(Clone)]
pub struct AppState(Arc<AppStateInner>);

pub struct AppStateInner {
    #[allow(dead_code)]
    pub config: AppConfig,
    users: Arc<UserMap>,
    dk: DecodingKey,
}

impl TokenVerify for AppState {
    type Error = AppError;

    fn verify(&self, token: &str) -> Result<User, AppError> {
        Ok(self.dk.verify(token)?)
    }
    
}

const INDEX_HTML: &str = include_str!("../index.html");

pub fn get_router() -> (Router, AppState) {
    let config = AppConfig::load().expect("failed to load noify config");
    let state = AppState::new(config);
    let app = Router::new()
    .route("/events", get(sse_handler))
    .layer(from_fn_with_state(state.clone(), verify_token::<AppState>))
        .route("/", get(index_handler))
        .with_state(state.clone());
    (app, state)
}
async fn index_handler() -> impl IntoResponse {
    Html(INDEX_HTML)
}



impl Deref for AppState {
    type Target = AppStateInner;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
    
}

impl AppState {
    pub fn new(config: AppConfig) -> Self {
        let dk = DecodingKey::load(&config.auth.pk).expect("failed to load pk");
        let users: Arc<DashMap<u64, broadcast::Sender<Arc<AppEvent>>>> = Arc::new(DashMap::new());
        AppState(Arc::new(AppStateInner { config,users,dk}))
    }
}